
#ifndef __tenacitas_interpreter__symbol__h__
#define __tenacitas_interpreter__symbol__h__


// =============================================================================
/** @file In this file are defined the classes tenacitas::interpreter::symbol,
    tenacitas::interpreter::symbol::value, tenacitas::interpreter::symbol::type,
    the template class tenacitas::interpreter::symbols_info, the typedefs
    tenacitas::interpreter::symbols_types and
    tenacitas::interpreter::symbols_values 

    @author Rodrigo Canellas - rodrigo.canellas@gmail.com   */



// =============================================================================
//                                 C++ Headers

#include <string>
#include <list>
#include <iostream>


// =============================================================================
//                                 3rds Headers





// =============================================================================
//                                 Our Headers

#include <tenacitas.memory/ptr.h>



// =============================================================================
//                                 Namespaces
using namespace std;





// =============================================================================
//                                 Macro Contants

/**  @brief */





// =============================================================================
//                                 Macro Commands

/** @brief   */




/** @brief Namespace of the organization */
namespace tenacitas {
    /** @brief Identifiers to allow the creation of a interpreter */
    namespace interpreter {

        // =====================================================================
        //                             Typedefs

        /** @brief */



        // =====================================================================
        //                             Pre-Declarations



        // =====================================================================
        //                             Attributes

        /** @brief    */





        // =====================================================================
        //                             Functions

        /** @brief */





        // =====================================================================
        //                             Classes

        /** @brief Represents a symbol read from the text being interpreted

            A symbol contains a value, usualy called lexema, which is the string
            read from the text being analysed. 

            A symbol has a type, like "integer", "variable_identifier" or
            "reserved_word". The type of a symbol is determined by a
            tenacitas::interpreter::scanner object.

            @nosubgrouping */
        class symbol {

        public:


            /** @brief The value, also called lexema, of the @p symbol.

                This is the string read from the input text.

                @nosubgrouping */
            class value {
                // ------------------------------------------------------------
                //                 symbol::value
                /// @name                  Friends
                /// @{

                /** @brief Allows the contents of a @p value object to be
                    streamed */ 
                friend ostream & operator << ( ostream & p_out,
                                               const symbol::value & p_value ) {
                    p_out << p_value.m_string;
                    return p_out;
                }
                
                /// @}                     ----------

            public:

                // -------------------------------------------------------------
                //                 symbol::value
                /// @name                  Public Constructors
                /// @{ 

                /** @brief Destructor */
                ~value ( ) ;

                /** @brief Constructor

                    @param [in] p_string is the string corresponding to the
                    value of the symbol  */
                value ( const string & p_string = "!!dummy_value!!" ) ;

                /// @}                     ----------

                
                // -------------------------------------------------------------
                //                 symbol::value
                /// @name                  Public Operators
                /// @{

                /** @brief Automatic conversion of the @p value to a string
                    object */ 
                operator string ( ) const ;
                
                /** @brief Equal-to operator */    
                bool operator == ( const value & p_value ) const;

                /** @brief Not-equal-to operator */
                bool operator != ( const value & p_value ) const;

                /** @brief Assignment operator */ 
                value & operator = ( const value & p_value ) ;
	    
                /// @}                     ----------

                // -------------------------------------------------------------
                //                 symbol::value
                /// @name                  Public Attributes
                /// @{

                /** @brief Very special tenacitas::interpreter::value,
                    indicating that all the input text was analysed  */
                static const value eot;
            
                /// @}                     ----------
            
            private:

                // -------------------------------------------------------------
                //                 symbol::value
                /// @name                  Private Attributes
                /// @{

                /** @brief The value of the @p symbol */ 
                string m_string;
            
                /// @}                     ----------

            };


            /** @brief The type of the @p symbol, like "integer",
                "variable_identifier" or "reserved_word". 

                @nosubgrouping */
            class type {

                // -------------------------------------------------------------
                //                 symbol::type
                /// @name                  Friends
                /// @{

                /** @brief Allows the contents of a @p type object to be
                    streamed */ 
                
                friend ostream & operator << ( ostream & p_out,
                                               const type & p_type ) {
                    p_out << p_type.m_string;
                    return p_out;
                }
                /// @}                     ----------

            public:

                // -------------------------------------------------------------
                //                 symbol::type
                /// @name                  Public Constructors
                /// @{ 

                /** @brief Destructor */
                ~type ( ) ;

                /** @brief Constructor

                    @param [in] p_string is the string definig the @p type, like
                    "integer", "variable_identifier" or "reserved_word" */
                type ( const string & p_string  = "!!dummy_type!!" ) ;

                /// @}                     ----------

                // -------------------------------------------------------------
                //                 symbol::type
                /// @name                  Public Operators
                /// @{

                /** @brief Automatic conversion of the @p type to a string
                    object */
                operator string ( ) const ;
	    
                /** @brief Equal-to operator */    
                bool operator == ( const type & p_type ) const;

                /** @brief Not-equal-to operator */    
                bool operator != ( const type & p_type ) const;

                /** @brief Assignment operator */    
                type & operator = ( const type & p_type ) ;
	    
                /// @}                     ----------

                // -------------------------------------------------------------
                //                 symbol::type
                /// @name                  Public Attributes
                /// @{

                /** @brief Very special tenacitas::interpreter::type,
                    indicating that all the input text was analysed  */
                static const type eot;
            
                /// @}                     ----------

            private:

                // -------------------------------------------------------------
                //                 symbol::type
                /// @name                  Private Attributes
                /// @{

                /** @brief The type of the @p symbol */
                string m_string;
            
                /// @}                     ----------

            };


            // -----------------------------------------------------------------
            //                         symbol
            /// @name                  Public Constructors
            /// @{ 

            /** @brief Constructor

                @param [in] p_value is the tenacitas::interpreter::symbol::value
                of this @p symbol

                @param [in] p_type is the tenacitas::interpreter::symbol::type
                of this @p symbol */
            symbol ( const symbol::value & p_value, const symbol::type & p_type );

            
            /** @brief Destructor */
            virtual ~symbol ( );

            /// @}                     ----------

            // -----------------------------------------------------------------
            //                         symbol
            /// @name                  Public Accessors
            /// @{

            /** @brief Retrieves the tenacitas::interpreter::symbol::value of
                this @p symbol */
            const symbol::value & get_value ( ) const;

            /** @brief Retrieves the tenacitas::interpreter::symbol::type of this
                @p symbol  */
            const symbol::type & get_type ( ) const;

            /** @brief Modifies the tenacitas::interpreter::symbol::value of the
                @p symbol

                @param [in] p_symbol_value is the new @p
                tenacitas::interpreter::symbol::value of the @p symbol */ 
            void set_value ( const symbol::value & p_symbol_value ) ;

            /** @brief Modifies the tenacitas::interpreter::symbol::type of the
                @p symbol

                @param [in] p_symbol_value is the new @p
                tenacitas::interpreter::symbol::type of the @p symbol */ 
            void set_type ( const symbol::type & p_symbol_type ) ;

            /// @}                     ----------

            // -----------------------------------------------------------------
            //                         symbol
            /// @name                  Public Operators
            /// @{

            /** @brief Equal-to operator */
            bool operator == ( const symbol & p_symbol ) const;

            /** @brief Not-equal-to operator */
            bool operator != ( const symbol & p_symbol ) const;

            /** @brief Assingment operator */
            symbol & operator = ( const symbol & p_symbol ) ;
            
            /// @}                     ----------

        private:
            // -----------------------------------------------------------------
            //                         symbol
            /// @name                  Private Attributes
            /// @{

            /** @brief The tenacitas::interpreter::symbol::value of the symbol

                This is actually the string read from the text being
                interpreted */
            symbol::value  m_value;
            
            /** @brief The tenacitas::interpreter::symbol::type of the @p
                symbol  */
            symbol::type m_type;
            
            /// @}                     ----------

        };





        /** @brief A collection to constant references to an information of a 
            tenacitas::interpreter::symbol object

            The type parameter @p t_symbol_info can be
            tenacitas::interpreter::symbol::value or
            tenacitas::interpreter::symbol::type 

            @nosubgrouping */
        template <typename t_symbol_info>
        class symbols_info {

        public:
            // -----------------------------------------------------------------
            //                         symbols_info
            /// @name                  Public Internal Types
            /// @{ 

            /** @brief Type of information stored */
            typedef t_symbol_info symbol_info;


            /** @brief Reference to the information stored */
            typedef
            typename list<memory::ptr<const t_symbol_info> >::const_iterator
            const_iterator ;
            
            /// @}                     ----------

            // -----------------------------------------------------------------
            //                         symbols_info
            /// @name                  Public Constructors
            /// @{ 

            /** @brief Constructor

                @param p_info is a string containg space separeted @p
                symbol_info objects, , like "decimal_integer real", if @p
                symbo_info is tenacitas::interpreter::symbol::type; or like "= ==
                ;" if @p symbo_info is tenacitas::interpreter::symbol::value */
            symbols_info ( const string & p_values ) ;


            /** @brief Destructor */
            ~symbols_info ( ) ;

            /// @}                     ----------

            // -----------------------------------------------------------------
            //                         symbols_info
            /// @name                  Public Accessors
            /// @{

            /** @brief Tries to find a constant reference to an object of @p
                t_symbol_info based on a @p t_symbol_info object

                @param p_symbol_info is the @p t_symbol_info used as base to
                find a reference to a @p t_symbol_info

                @return a valid constante reference to a @p t_symbol_info, if
                found

                @return a null reference, if not */
            memory::ptr<const t_symbol_info>
            find ( const t_symbol_info & p_info ) const;


            /** @brief Adds a @p t_symbol_info to the collection 

                @param [in] p_symbol_info is the @p t_symbol_info we want to
                insert into the collection
                
                @return a reference to the just insert @p p_symbol_info */
            memory::ptr<const t_symbol_info>
            add ( const t_symbol_info & p_symbol_info ) ;

            /** @brief Returns a reference to the first <tt> memory::ptr<const
                t_symbol_info> </tt> of the collection */
            const_iterator  begin ( ) const;

            /** @brief Returns a reference to the end of the of the
                collection  */
            const_iterator end ( ) const;
            
            /// @}                     ----------

        private:

            // -----------------------------------------------------------------
            //                         symbols_info
            /// @name                  Private Internal Types
            /// @{

            /** @brief type of the collection of constant references to @p
                t_symbol_info objects */
            typedef list<memory::ptr<const t_symbol_info> > symbols_info_list;
            
            /// @}                     ----------


            // -----------------------------------------------------------------
            //                         symbols_info
            /// @name                  Private Processors
            /// @{

            /** @brief Decodes a string to a list of @p symbols_info_list object 

                @param p_info is a string containg space separeted @p
                symbol_info objects, , like "decimal_integer real", if @p
                symbo_info is tenacitas::interpreter::symbol::type; or like "= ==
                ;" if @p symbo_info is tenacitas::interpreter::symbol::value */
            void string2list ( const string & p_info ) ;

            /// @}                     ----------


            // -----------------------------------------------------------------
            //                         symbols_info
            /// @name                  Private Attributes
            /// @{

            /** @brief The collection of constant references to @p t_symbol_info
                objects  */ 
            symbols_info_list m_symbols_info_list;
            
            /// @}                     ----------

        };
        

        // =====================================================================
        //                             Typedefs

        /** @brief Specialization of the tenacitas::interpreter::symbols_info
            collection to store constant references to
            tenacitas::interpreter::symbol::value objects */
        typedef symbols_info<symbol::value> symbols_values;

        /** @brief Specialization of the tenacitas::interpreter::symbols_info
            collection to store constant references to
            tenacitas::interpreter::symbol::type objects */
        typedef symbols_info<symbol::type> symbols_types;



        // =====================================================================
        //                             Classes


        /** @brief Collection of references to tenacitas::interpreter::symbol
            objects  

            @nosubgrouping */
        class symbols {

        public:

            // -----------------------------------------------------------------
            //                         symbols
            /// @name                  Public Internal Types
            /// @{

            typedef list<memory::ptr<symbol> >::iterator iterator;
            typedef list<memory::ptr<symbol> >::const_iterator const_iterator;
            typedef list<memory::ptr<symbol> >::size_type size_type;
            

            /// @}                     ----------

            // -----------------------------------------------------------------
            //                         symbols
            /// @name                  Public Constructors
            /// @{ 

            /** @brief Constructor */
            symbols ( ) ;

            /** @brief  */
            ~symbols ( ) ;
            
            /// @}                     ----------

            // -----------------------------------------------------------------
            //                         symbols
            /// @name                  Public Accessors
            /// @{

            /** @brief Adds a tenacitas::interpreter::symbol to the collection

                @param p_symbol is the @p symbol to be added to the collection */ 
            void add ( memory::ptr<symbol> p_symbol ) ;

            /** @brief References the first <tt>
                tenacitas::memory::ptr<tenacitas::interpreter::symbol> </tt> of
                the collection */ 
            iterator begin ( ) ;

            /** @brief The end of the collection */ 
            iterator end ( ) ;

            /** @brief References the first <tt>
                tenacitas::memory::ptr<tenacitas::interpreter::symbol> </tt> of
                the collection */ 
            const_iterator begin ( ) const ;

            /** @brief The end of the collection */ 
            const_iterator end ( ) const ;

            /** @brief Erases symbols from the collection

                @param [in] p_begin is a reference to the first @p symbol that
                should be deleted

                @param [in] p_end is a reference to the @p symbol imediately
                after the last @p symbol to be deleted */
            void erase ( iterator p_begin, iterator p_end ) ;
            
            	  	    
            /// @}                     ----------

        private:
            // -----------------------------------------------------------------
            //                         symbols
            /// @name                  Private Attributes
            /// @{

            /** @brief The collection of <tt>
                tenacitas::memory::ptr<tenacitas::interpreter::symbol </tt> */ 
            list<memory::ptr<symbol> > m_list;
	    
            /// @}                     ----------

        };        
    }
}

// ====================================================================
// ====================================================================
// ====================================================================

//         I M P L E M E N T A T I O N 

// ====================================================================
// ====================================================================
// ====================================================================


using namespace tenacitas::interpreter;


// ####################################################################
//                                    symbols_info

template <typename t_symbol_info>
symbols_info<t_symbol_info>::
symbols_info ( const string & p_info ) :
    m_symbols_info_list ( ) {

    string2list ( p_info ) ;
            
}
        

// --------------------------------------------------------------------
template <typename t_symbol_info>
symbols_info<t_symbol_info>::
~symbols_info ( ) { }


// --------------------------------------------------------------------
template <typename t_symbol_info>
memory::ptr<const t_symbol_info>
symbols_info<t_symbol_info>::
find ( const t_symbol_info & p_info ) const {

    memory::ptr<const t_symbol_info> rc ;

    for ( const_iterator i = begin ( ) ; i != end ( ) ; ++i ) {
        if (  **i == p_info ) {
            rc = *i;
            break;
        }
    }
    return rc;
}

// --------------------------------------------------------------------
template <typename t_symbol_info>
memory::ptr<const t_symbol_info>
symbols_info<t_symbol_info>::
add ( const t_symbol_info & p_info ) {

    memory::ptr<const t_symbol_info> rc = find ( p_info );

    if (  rc == 0 ) {
        m_symbols_info_list.push_front
            ( memory::ptr<t_symbol_info> ( new t_symbol_info ( p_info ) ) ) ;

        rc = *m_symbols_info_list.begin ( ) ;
    }
    return rc;
}

// --------------------------------------------------------------------
template <typename t_symbol_info>
void
symbols_info<t_symbol_info>::
string2list ( const string & p_info )  {

    size_t p1 = 0;
    size_t p2 = 0;
    size_t size = p_info.size ( );

  lb_init:
    {
        while ( true ) {
            if ( p2 >= size ) goto lb_last_info;
        
            if ( p_info [p2] == ' ' ) goto lb_middle_info;

            ++p2;
        }
    }
    

  lb_middle_info:
    {
        symbol_info l_symbol_info ( string  ( & p_info [p1],
                                              & p_info [p2] ) ) ;

        /// adding it to the collection
        add ( l_symbol_info ) ;

        /// updating the positioners
        ++p2;
        p1 = p2;

        goto lb_init;
    }
    
  lb_last_info:
    {
        
        symbol_info l_symbol_info ( string  ( & p_info [p1],
                                              & p_info [p_info.size( )] ) ) ;

        /// adding it to the collection
        add ( l_symbol_info ) ;
    }
    
}


// --------------------------------------------------------------------
template <typename t_symbol_info>
typename symbols_info<t_symbol_info>::const_iterator
symbols_info<t_symbol_info>::
begin ( ) const {return m_symbols_info_list.begin( ) ;}

// --------------------------------------------------------------------
template <typename t_symbol_info>
typename symbols_info<t_symbol_info>::const_iterator
symbols_info<t_symbol_info>::
end ( ) const {return m_symbols_info_list.end( ) ;}


#endif
